import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MaxNLocator, MultipleLocator
from matplotlib.ticker import ScalarFormatter
from matplotlib.ticker import LogLocator
import matplotlib as mpl

def read_and_process_data(log_file, st, ed, bin_size=200000):
    max_counts = {}
    min_counts = {}
    median_counts = {}
    
    current_max = 0
    current_min = float('inf')
    current_sent_bytes = []

    with open(log_file, 'r') as f:
        for line in f:
            if line.startswith('Time'):
                # 计算中位数
                median_value = np.median(current_sent_bytes)
                
                # 计算字节区间
                max_bin = int(current_max // bin_size) * bin_size
                min_bin = int(current_min // bin_size) * bin_size
                median_bin = int(median_value // bin_size) * bin_size
                
                # 记录最大值、最小值和中位数的区间统计
                max_counts[max_bin] = max_counts.get(max_bin, 0) + 1
                min_counts[min_bin] = min_counts.get(min_bin, 0) + 1
                median_counts[median_bin] = median_counts.get(median_bin, 0) + 1
                        
                # 重置统计值
                current_max = 0
                current_min = float('inf')
                current_sent_bytes = []
            elif 'sentBytes' in line:
                # 提取sentBytes
                parts = line.split()
                sent_bytes_str = parts[3].replace('KB', '')
                sent_bytes = float(sent_bytes_str) * 1024  # 转换成字节

                # 更新当前最大值、最小值和添加到当前的字节数据列表
                current_max = max(current_max, sent_bytes)
                current_min = min(current_min, sent_bytes)
                current_sent_bytes.append(sent_bytes)

    # 转换为可用于绘图的数组
    max_bins = sorted(max_counts.keys())
    min_bins = sorted(min_counts.keys())
    median_bins = sorted(median_counts.keys())

    max_values = [max_counts[bin] for bin in max_bins]
    min_values = [min_counts[bin] for bin in min_bins]
    median_values = [median_counts[bin] for bin in median_bins]
    
    return max_bins, max_values, min_bins, min_values, median_bins, median_values

def find_best_threshold(A_key, B_value):
    best_diff = float('inf')  # 用于存储最小的数量差
    best_threshold = None    # 用于存储最佳的阈值
    
    # 遍历所有可能的分割点
    for i in range(1, len(A_key)):
        # 分割点在A_key[i-1]和A_key[i]之间
        left = B_value[:i]
        right = B_value[i:]
        
        # 计算左右两边的数量差
        diff = abs(sum(left) - sum(right))
        
        # 如果当前差值更小，则更新最佳阈值
        if diff < best_diff:
            best_diff = diff
            best_threshold = A_key[i]  # A_key[i]是最接近分割的阈值
    
    return best_threshold, best_diff

def plot_sentbytes(max_bins, max_values, min_bins, min_values, median_bins, median_values, output_file):
    # 调整数据
    max_bins = np.array(max_bins) / 1e6
    min_bins = np.array(min_bins) / 1e6
    median_bins = np.array(median_bins) / 1e6

    thre, diff = find_best_threshold(median_bins, median_values)
    
    # 绘图
    plt.figure(figsize=(24, 8))
    
    lw = 5
    ms = 12
        
    # 绘制最大值曲线
    plt.plot(max_bins, max_values, marker='o', linestyle='-', color='#5383ec', linewidth=lw, markersize=ms, label='Max SentBytes')
    
    # 绘制最小值曲线
    plt.plot(min_bins, min_values, marker='s', linestyle='-', color='#d85140', linewidth=lw, markersize=ms, label='Min SentBytes')
    
    # 绘制中位数曲线
    plt.plot(median_bins, median_values, marker='^', linestyle='-', color='#58a65c', linewidth=lw, markersize=ms, label='Median SentBytes')
    
    plt.axvline(x=thre, color='k', linestyle='-.', linewidth=5, alpha=0.7)
    
    # 设置纵坐标为对数坐标
    plt.yscale('log')

    # 设置坐标轴标题
    font1 = {'weight': 'normal', 'size': 40}
    X_name = "SentBytes Range(MB)"
    plt.xlabel(X_name, fontdict=font1)
    Y_name = "Frequency"
    plt.ylabel(Y_name, fontdict=font1)


    # 添加刻度
    plt.tick_params(labelsize=40)

    # 显示更多刻度

    # 启用小刻度，并显示
    plt.minorticks_on()

    # 自定义小刻度间隔，减少小刻度的密度
    plt.gca().xaxis.set_minor_locator(MultipleLocator(0.5))  # 每5显示一个小刻度
    plt.gca().yaxis.set_major_locator(LogLocator(base=10.0, numticks=6))
    # 设置主刻度和小刻度的样式
    plt.tick_params(which='major', axis='x', direction='in', length=10, width=4)  # 主刻度和小刻度的样式
    plt.tick_params(which='minor', axis='x', direction='in', length=4, width=4)  # 主刻度和小刻度的样式
    plt.tick_params(which='major', axis='y', direction='in', length=10, width=4)  # 主刻度和小刻度的样式
    plt.tick_params(which='minor', axis='y', direction='in', length=4, width=4)  # 主刻度和小刻度的样式
    # 添加图例
    plt.legend(loc='upper right', ncol=1, prop={'size': 30, 'weight': 'normal'})
    
    # 保存图片
    plt.savefig(output_file + '.png', format='png', dpi=300, bbox_inches='tight')
    plt.savefig(output_file + '.pdf', format='pdf', dpi=300, bbox_inches='tight')
    plt.close()

# 主程序
if __name__ == "__main__":
    log_file = 'run_bytes.log'
    st = 3050000000  # 起始时间（ns）
    ed = 4000000000  # 结束时间（ns）
    output_file = 'img/sendbytes'

    max_bins, max_values, min_bins, min_values, median_bins, median_values = read_and_process_data(log_file, st, ed)
    plot_sentbytes(max_bins, max_values, min_bins, min_values, median_bins, median_values, output_file)
    print(f"图表已保存为 {output_file}")